//==============================================================================
//
//         DImageHeader - the Image Header class in the ofc-library
//
//               Copyright (C) 2003  Dick van Oudheusden
//  
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this library; if not, write to the Free
// Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//==============================================================================
// 
//  $Date: 2004-02-20 20:16:34 $ $Revision: 1.8 $
//
//==============================================================================

#include "ofc/DImageHeader.h"



#if _INTERFACE_

#include "ofc/config.h"

#include "ofc/DDataReadable.h"

#include "ofc/DData.h"
#include "ofc/DText.h"

// DImageHeaderType

typedef enum
{
  DIM_UNKN = -1,  // unknown image format
  DIM_JPEG,       // jpeg image format
  DIM_GIF,        // gif image format
  DIM_PNG,        // png image format
  DIM_BMP,        // bmp image format
  DIM_PCX,        // pcx image format
  DIM_IFF,        // iff image format
  DIM_RAS,        // ras image format
  DIM_PBM,        // pbm image format
  DIM_PGM,        // pgm image format
  DIM_PPM,        // ppm image format
  DIM_PSD,        // psd image format
  DIM_SWF,        // swf image format
  DIM_TIFF        // tiff image format
} DImageHeaderType;

// The DImageHeader class implements a number of methods for determining the
// type of an image file. Due to the fact that only small tests are performed
// on the image files, the determination is not full proof. In the future this 
// will become a factory for image objects.

@interface DImageHeader : Object
{
@private
  DImageHeaderType _type;    // the image type (DIM_UNKN,DIM_JPEG,DIM_GIF,DIM_PNG,DIM_BMP,DIM_PCX,DIM_IFF,DIM_RAS,DIM_PBM,DIM_PGM,DIM_PPM,DIM_PSD,DIM_SWF)
}

#endif



#if _PRIVATE_

static char *_extensions[] =
{
    "jpeg",
    "gif", 
    "png", 
    "bmp",
    "pcx", 
    "iff", 
    "ras", 
    "pbm", 
    "pgm", 
    "ppm", 
    "psd", 
    "swf",
    "tiff"
};

static char *_mime_types[] =
{
    "image/jpeg", 
    "image/gif", 
    "image/png", 
    "image/bmp", 
    "image/pcx", 
    "image/iff", 
    "image/ras", 
    "image/x-portable-bitmap", 
    "image/x-portable-graymap", 
    "image/x-portable-pixmap", 
    "image/psd", 
    "application/x-shockwave-flash",
    "image/tiff"
};

#endif



@implementation DImageHeader


//// Constructors

//
// Initialise an empty image header object
//
// @return the instance
//

- (DImageHeader *) init
{
  [super init];

  _type  = DIM_UNKN;
  
  return self;
}

//
// Initialise with a data readable
//
// @param file     the file
//
// @return the instance
//

- (DImageHeader *) init :(id <DDataReadable>) file
{
  [self init];

  [self inspect :file];
  
  return self;
}


//// Image info methods

//
// Return the type of the image (or DIM_UNKN for unknown)
//
// @return the type
//

- (DImageHeaderType) type
{
  return _type;
}

//
// Return the extension for the type of image
//
// @return the extension (or NULL for unknown type)
//

- (const char *) extension
{
  if ((_type <= DIM_UNKN) || (_type > DIM_TIFF))
    return NULL;
  else
    return _extensions[_type];
}

//
// Return the mime type for the type of image
//
// @return the mime type (or NULL for unknown type)
//

- (const char *) mime_type
{
  if ((_type <= DIM_UNKN) || (_type > DIM_TIFF))
    return NULL;
  else
    return _mime_types[_type];
}


//// Main method

//
// Inspect the image file
//
// @param file     the file to be inspected
//
// @return success
//

- (BOOL) inspect :(id <DDataReadable>) file
{
  long offset = [file tell];

  _type = DIM_UNKN;
  
  if (offset >= 0)
  {
    if ([file seek :0 :0])
    {
      DData *data = [file readData :32];

      if ((data != nil) && ([data length] >= 2))
      {
        unsigned char b1 = [data get :0];
        unsigned char b2 = [data get :1];

        if ((b1 == 0xff) && (b2 == 0xd8))
        {
          _type = DIM_JPEG;
        }
        else if ((b1 == 'G') && (b2 == 'I'))
        {
          _type = DIM_GIF;
        }
        else if ((b1 == 0x89) && (b2 == 'P'))
        {
          _type = DIM_PNG;
        }
        else if ((b1 == 'B') && (b2 == 'M'))
        {
          _type = DIM_BMP;
        }
        else if ((b1 == 0x0a) && (b2 < 0x06))
        {
          _type = DIM_PCX;
        }
        else if ((b1 == 'F') && (b2 == 'O'))
        {
          _type = DIM_IFF;
        }
        else if ((b1 == 0x59) && (b2 == 0xa6))
        {
          _type = DIM_RAS;
        }
        else if ((b1 == 'P') && ((b2 == '1') || (b2 == '4')))
        {
          _type = DIM_PBM;
        }
        else if ((b1 == 'P') && ((b2 == '2') || (b2 == '5')))
        {
          _type = DIM_PGM;
        }
        else if ((b1 == 'P') && ((b2 == '3') || (b2 == '6')))
        {
          _type = DIM_PPM;
        }
        else if ((b1 == '8') && (b2 == 'B'))
        {
          _type = DIM_PSD;
        }
        else if ((b1 == 'F') && (b2 == 'W'))
        {
          _type = DIM_SWF;
        }
        else if (((b1 == 'I') && (b2 == 'I')) || 
                 ((b1 == 'M') && (b2 == 'M')))
        {
          _type = DIM_TIFF;
        }
      }
    }
    [file seek :offset :0];
  }
  
  return (_type != DIM_UNKN);
}

@end

/*===========================================================================*/

